package cn.elwy.rcp.ui.table.internal.parser;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ViewerFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.elwy.common.util.AssertUtil;
import cn.elwy.common.util.ConvertTypeUtil;
import cn.elwy.rcp.ui.table.TableConfigFactory;
import cn.elwy.rcp.ui.table.TablePlugin;
import cn.elwy.rcp.ui.table.adapter.ButtonBarAdapter;
import cn.elwy.rcp.ui.table.adapter.TableConfigAdapter;
import cn.elwy.rcp.ui.table.adapter.TableEditorAdapter;
import cn.elwy.rcp.ui.table.format.ColumnFormat;
import cn.elwy.rcp.ui.table.listener.TablePaneAction;
import cn.elwy.rcp.ui.table.listener.TablePaneActionGroup;
import cn.elwy.rcp.ui.table.listener.TablePaneButtonListener;
import cn.elwy.rcp.ui.table.listener.TablePaneCheckStateListener;
import cn.elwy.rcp.ui.table.listener.TablePaneDoubleClickListener;
import cn.elwy.rcp.ui.table.listener.TablePaneDragSourceListener;
import cn.elwy.rcp.ui.table.listener.TablePaneDropTargetListener;
import cn.elwy.rcp.ui.table.listener.TablePaneKeyListener;
import cn.elwy.rcp.ui.table.listener.TablePaneMouseListener;
import cn.elwy.rcp.ui.table.listener.TablePanePropertyListener;
import cn.elwy.rcp.ui.table.listener.TablePaneSelectionListener;
import cn.elwy.rcp.ui.table.model.ButtonBarInfo;
import cn.elwy.rcp.ui.table.model.ButtonCompositeInfo;
import cn.elwy.rcp.ui.table.model.ButtonInfo;
import cn.elwy.rcp.ui.table.model.ColumnInfo;
import cn.elwy.rcp.ui.table.model.TableInfo;
import cn.elwy.rcp.ui.table.model.ViewerFilterInfo;
import cn.elwy.rcp.ui.table.provider.TablePaneCheckStateProvider;
import cn.elwy.rcp.ui.util.SWTUtil;

public class TablePaneParser {

  private static final String PUSH = "PUSH";
  private static final String CENTER = "CENTER";
  private static final String LEFT = "LEFT";
  private static final String NONE = "NONE";

  private Logger logger = LoggerFactory.getLogger(TablePaneParser.class);

  public TablePaneParser() {
  }

  public void parseTablePanes() {
    IConfigurationElement[] tablePanes = Platform.getExtensionRegistry()
        .getConfigurationElementsFor(TablePlugin.PLUGIN_ID, "tablePanes");
    Map<String, TableInfo> tableInfoMap = TableConfigFactory.getTableInfoMap();
    for (IConfigurationElement tablePane : tablePanes) {
      try {
        TableInfo tableInfo = parseTablePane(tablePane);
        tableInfoMap.put(tableInfo.getId(), tableInfo);
      } catch (Exception e) {
        logger.error(e.getMessage(), e);
      }
    }
  }

  private TableInfo parseTablePane(IConfigurationElement tablePaneElement) {
    IConfigurationElement[] columnElements = tablePaneElement.getChildren("columns");
    if (columnElements.length == 0) {
      throw new RuntimeException("尚未配置表格columns");
    }
    TableInfo tableInfo = new TableInfo();

    parseBaseInfo(tablePaneElement, tableInfo);
    parseColumnKeys(columnElements[0], tableInfo);
    parseColumnInfos(columnElements[0], tableInfo);

    String contentProviderAttribute = tablePaneElement.getAttribute("contentProvider");
    if (AssertUtil.isNotEmpty(contentProviderAttribute)) {
      ITreeContentProvider contentProvider = createInstence(tablePaneElement, "contentProvider");
      tableInfo.setContentProvider(contentProvider);
    }
    String labelProviderAttribute = tablePaneElement.getAttribute("labelProvider");
    if (AssertUtil.isNotEmpty(labelProviderAttribute)) {
      IBaseLabelProvider labelProvider = createInstence(tablePaneElement, "labelProvider");
      tableInfo.setLabelProvider(labelProvider);
    }

    parseViewerFilters(tablePaneElement, tableInfo);
    parseActions(tablePaneElement, tableInfo);

    String checkStateProviderAttribute = tablePaneElement.getAttribute("checkStateProvider");
    if (AssertUtil.isNotEmpty(checkStateProviderAttribute)) {
      TablePaneCheckStateProvider checkStateProvider = createInstence(tablePaneElement, "checkStateProvider");
      tableInfo.setCheckStateProvider(checkStateProvider);
    }
    String tableEditorAdapterAttribute = tablePaneElement.getAttribute("tableEditorAdapter");
    if (AssertUtil.isNotEmpty(tableEditorAdapterAttribute)) {
      TableEditorAdapter tableEditorAdapter = createInstence(tablePaneElement, "tableEditorAdapter");
      tableInfo.setTableEditorAdapter(tableEditorAdapter);
    }
    String tableConfigAdapterAttribute = tablePaneElement.getAttribute("tableConfigAdapter");
    if (AssertUtil.isNotEmpty(tableConfigAdapterAttribute)) {
      TableConfigAdapter tableConfigAdapter = createInstence(tablePaneElement, "tableConfigAdapter");
      tableInfo.setTableConfigAdapter(tableConfigAdapter);
    }

    IConfigurationElement[] cslElement = tablePaneElement.getChildren("checkStateListener");
    if (cslElement.length > 0) {
      TablePaneCheckStateListener listener = createInstence(cslElement[0], "listener");
      tableInfo.setCheckStateListener(listener);
    }
    IConfigurationElement[] dclElements = tablePaneElement.getChildren("doubleClickListener");
    if (dclElements.length > 0) {
      TablePaneDoubleClickListener listener = createInstence(dclElements[0], "listener");
      tableInfo.setDoubleClickListener(listener);
    }
    IConfigurationElement[] dslElements = tablePaneElement.getChildren("dragSourceListener");
    if (dslElements.length > 0) {
      TablePaneDragSourceListener listener = createInstence(dslElements[0], "listener");
      tableInfo.setDragSourceListener(listener);
    }
    IConfigurationElement[] dtlElements = tablePaneElement.getChildren("dropTargetListener");
    if (dtlElements.length > 0) {
      TablePaneDropTargetListener listener = createInstence(dtlElements[0], "listener");
      tableInfo.setDropTargetListener(listener);
    }
    IConfigurationElement[] klElements = tablePaneElement.getChildren("keyListener");
    if (klElements.length > 0) {
      TablePaneKeyListener listener = (TablePaneKeyListener) createInstence(klElements[0], "listener");
      tableInfo.setKeyListener(listener);
    }
    IConfigurationElement[] mlElements = tablePaneElement.getChildren("mouseListener");
    if (mlElements.length > 0) {
      TablePaneMouseListener listener = createInstence(mlElements[0], "listener");
      tableInfo.setMouseListener(listener);
    }
    IConfigurationElement[] pclElements = tablePaneElement.getChildren("propertyChangeListener");
    if (pclElements.length > 0) {
      TablePanePropertyListener listener = createInstence(pclElements[0], "listener");
      tableInfo.setPropertyChangedListener(listener);
    }
    IConfigurationElement[] sclElements = tablePaneElement.getChildren("selectionChangedListener");
    if (sclElements.length > 0) {
      TablePaneSelectionListener listener = createInstence(sclElements[0], "listener");
      tableInfo.setSelectionChangedListener(listener);
    }

    parseButtonCompositeInfo(tablePaneElement, tableInfo);

    return tableInfo;
  }

  private void parseBaseInfo(IConfigurationElement element, TableInfo tableInfo) {
    String tableId = element.getAttribute("id");
    tableInfo.setId(tableId);
    boolean canCustomConfig = ConvertTypeUtil.toBoolean(element.getAttribute("isCustomConfig"), true);
    tableInfo.setCanCustomConfig(canCustomConfig);

    tableInfo.setName(element.getAttribute("name"));
    String style = element.getAttribute("style");
    if (AssertUtil.isEmpty(style)) {
      style = NONE;
    }
    tableInfo.setStyleName(style);
    // tableInfo.setStyle(SWTUtil.toSWTConstant(style, NONE));
    tableInfo.setType(element.getAttribute("type"));

    boolean headerVisible = ConvertTypeUtil.toBoolean(element.getAttribute("headerVisible"), true);
    tableInfo.setHeaderVisible(headerVisible);
    boolean lineVisible = ConvertTypeUtil.toBoolean(element.getAttribute("lineVisible"), true);
    tableInfo.setLineVisible(lineVisible);
    int lineHeight = ConvertTypeUtil.toInteger(element.getAttribute("lineHeight"), 16);
    tableInfo.setLineHeight(lineHeight);
    boolean multipleSelection = ConvertTypeUtil.toBoolean(element.getAttribute("multipleSelection"), true);
    tableInfo.setMultipleSelection(multipleSelection);
    boolean isAutoRefresh = ConvertTypeUtil.toBoolean(element.getAttribute("isAutoRefresh"), false);
    tableInfo.setAutoRefresh(isAutoRefresh);
    int defaultRefreshInterval = ConvertTypeUtil.toInteger(element.getAttribute("defaultRefreshInterval"), 60);
    tableInfo.setDefaultRefreshInterval(defaultRefreshInterval);

    boolean canEditor = ConvertTypeUtil.toBoolean(element.getAttribute("canEditor"), false);
    tableInfo.setCanEditor(canEditor);
    boolean canSave = ConvertTypeUtil.toBoolean(element.getAttribute("canSave"), true);
    tableInfo.setCanSave(canSave);
    boolean canSort = ConvertTypeUtil.toBoolean(element.getAttribute("canSort"), true);
    tableInfo.setCanSort(canSort);
    boolean canSettingColumn = ConvertTypeUtil.toBoolean(element.getAttribute("canSettingColumn"), true);
    tableInfo.setCanSettingColumn(canSettingColumn);
  }

  private void parseColumnKeys(IConfigurationElement columnElement, TableInfo tableInfo) {
    String keysValue = columnElement.getAttribute("keys");
    if (keysValue != null) {
      String[] keysSplit = keysValue.split(",");
      ArrayList<String> columnKeys = new ArrayList<String>(keysSplit.length);
      for (String key : keysSplit) {
        columnKeys.add(key.trim());
      }
      tableInfo.setColumnKeys(columnKeys);
    }
  }

  private void parseColumnInfos(IConfigurationElement columnsElement, TableInfo tableInfo) {
    IConfigurationElement[] columnElements = columnsElement.getChildren("column");
    List<ColumnInfo> columnInfoList = new ArrayList<ColumnInfo>(columnElements.length);
    for (int i = 0; i < columnElements.length; i++) {
      ColumnInfo columnInfo = parseColumn(columnElements[i]);
      columnInfo.setOrder(i);
      columnInfoList.add(columnInfo);
    }
    tableInfo.setColumnInfoList(columnInfoList);
  }

  private void parseViewerFilters(IConfigurationElement tablePaneElement, TableInfo tableInfo) {
    IConfigurationElement[] viewerFilterElements = tablePaneElement.getChildren("viewerFilter");

    List<ViewerFilterInfo> viewerFilterInfoList = new ArrayList<ViewerFilterInfo>(viewerFilterElements.length);
    for (int i = 0; i < viewerFilterElements.length; i++) {
      IConfigurationElement viewerFilterElement = viewerFilterElements[i];
      IConfigurationElement[] classElements = tablePaneElement.getChildren("class");
      if (classElements.length < 1) {
        continue;
      }
      String id = viewerFilterElement.getAttribute("id");
      String name = viewerFilterElement.getAttribute("name");
      String description = viewerFilterElement.getAttribute("description");
      boolean activeByDefault = ConvertTypeUtil.toBoolean(viewerFilterElement.getAttribute("activeByDefault"), false);
      boolean visibleInUI = ConvertTypeUtil.toBoolean(viewerFilterElement.getAttribute("visibleInUI"), false);
      ViewerFilter viewerFilter = (ViewerFilter) createInstence(viewerFilterElement, "class");

      ViewerFilterInfo vf = new ViewerFilterInfo();
      vf.setId(id);
      vf.setName(name);
      vf.setDescription(description);
      vf.setActiveByDefault(activeByDefault);
      vf.setVisibleInUI(visibleInUI);
      vf.setViewerFilter(viewerFilter);

      viewerFilterInfoList.add(vf);
    }
    tableInfo.setViewerFilterList(viewerFilterInfoList);
  }

  private void parseActions(IConfigurationElement tablePaneElement, TableInfo tableInfo) {
    IConfigurationElement[] actionGroupElements = tablePaneElement.getChildren("actionGroup");
    for (int i = 0; i < actionGroupElements.length; i++) {
      IConfigurationElement viewerFilterElement = actionGroupElements[i];

      String actionGroupAttribute = viewerFilterElement.getAttribute("actionGroup");
      if (AssertUtil.isNotEmpty(actionGroupAttribute)) {
        TablePaneActionGroup tablePaneActionGroup = createInstence(viewerFilterElement, "actionGroup");
        tableInfo.setActionGroup(tablePaneActionGroup);
      }

      IConfigurationElement[] children = viewerFilterElement.getChildren("action");
      List<TablePaneAction> actionList = new ArrayList<TablePaneAction>(children.length);
      for (int j = 0; j < children.length; j++) {
        IConfigurationElement childrenElement = children[i];

        String actionAttribute = childrenElement.getAttribute("action");
        if (AssertUtil.isNotEmpty(actionAttribute)) {
          TablePaneAction tablePaneAction = createInstence(childrenElement, "action");

          String name = childrenElement.getAttribute("name");
          String index = childrenElement.getAttribute("index");
          String parent = childrenElement.getAttribute("parent");
          String actionType = childrenElement.getAttribute("actionType");
          String isEnabled = childrenElement.getAttribute("isEnabled");

          tablePaneAction.setName(name);
          tablePaneAction.setText(name);
          tablePaneAction.setIndex(index);
          tablePaneAction.setParent(parent);
          tablePaneAction.setIsEnabled(isEnabled);
          tablePaneAction.setActionType(actionType);

          actionList.add(tablePaneAction);
        }
      }
      tableInfo.setActionList(actionList);
    }
  }

  private ColumnInfo parseColumn(IConfigurationElement columnElement) {
    ColumnInfo columnInfo = new ColumnInfo();
    String columnId = columnElement.getAttribute("id");
    columnInfo.setId(columnId);
    String name = columnElement.getAttribute("name");
    columnInfo.setName(name);
    String style = columnElement.getAttribute("style");
    if (AssertUtil.isEmpty(style)) {
      style = LEFT;
    }
    columnInfo.setStyleName(style);
    // columnInfo.setStyle(SWTUtil.toSWTConstant(style, LEFT));

    String alignment = columnElement.getAttribute("alignment");
    if (AssertUtil.isEmpty(alignment)) {
      alignment = LEFT;
    }
    columnInfo.setAlignmentName(alignment);
    // columnInfo.setAlignment(SWTUtil.toSWTConstant(alignment, LEFT));

    boolean canVisible = ConvertTypeUtil.toBoolean(columnElement.getAttribute("canVisible"), true);
    columnInfo.setCanVisible(canVisible);

    boolean isVisible = ConvertTypeUtil.toBoolean(columnElement.getAttribute("visible"), true);
    columnInfo.setVisible(isVisible);

    int width = Integer.parseInt(columnElement.getAttribute("width"));
    columnInfo.setWidth(width);

    String formatAttribute = columnElement.getAttribute("columnFormat");
    if (AssertUtil.isNotEmpty(formatAttribute)) {
      ColumnFormat format = createInstence(columnElement, "columnFormat");
      String formatPattern = columnElement.getAttribute("formatPattern");
      columnInfo.setFormatPattern(formatPattern);
      format.setPattern(formatPattern);
      columnInfo.setColumnFormat(format);

    }

    boolean canEditor = ConvertTypeUtil.toBoolean(columnElement.getAttribute("canEditor"), false);
    columnInfo.setCanEditor(canEditor);

    return columnInfo;
  }

  private void parseButtonCompositeInfo(IConfigurationElement tablePaneElement, TableInfo tableInfo) {
    IConfigurationElement[] bcElements = tablePaneElement.getChildren("buttonComposite");
    if (bcElements.length == 0) {
      return;
    }

    List<ButtonCompositeInfo> buttonCompositeInfoList = new ArrayList<ButtonCompositeInfo>();
    for (IConfigurationElement bcElement : bcElements) {
      ButtonCompositeInfo buttonCompositeInfo = new ButtonCompositeInfo();
      String name = bcElement.getAttribute("name");
      buttonCompositeInfo.setName(name);
      String location = bcElement.getAttribute("location");
      buttonCompositeInfo.setLocation(location);

      IConfigurationElement[] buttonBarElements = bcElement.getChildren("buttonBar");
      if (buttonBarElements.length > 0) {
        List<ButtonBarInfo> buttonBarInfoList = new ArrayList<ButtonBarInfo>();
        for (IConfigurationElement bbElement : buttonBarElements) {
          ButtonBarInfo buttonBarInfo = parseButtonBarInfos(bbElement);
          buttonBarInfoList.add(buttonBarInfo);
        }
        buttonCompositeInfo.setButtonBarInfoList(buttonBarInfoList);
      }
      buttonCompositeInfoList.add(buttonCompositeInfo);
    }
    tableInfo.setButtonCompositeInfoList(buttonCompositeInfoList);
  }

  private ButtonBarInfo parseButtonBarInfos(IConfigurationElement bbElement) {
    ButtonBarInfo buttonBarInfo = new ButtonBarInfo();
    String name = bbElement.getAttribute("name");
    buttonBarInfo.setName(name);
    String styleType = bbElement.getAttribute("style");
    if (AssertUtil.isEmpty(styleType)) {
      styleType = NONE;
    }
    buttonBarInfo.setStyle(SWTUtil.toSWTConstant(styleType, NONE));

    String horizontalAlignment = bbElement.getAttribute("horizontalAlignment");
    buttonBarInfo.setHorizontalAlignment(SWTUtil.toSWTConstant(horizontalAlignment, LEFT));
    String verticalAlignment = bbElement.getAttribute("verticalAlignment");
    buttonBarInfo.setVerticalAlignment(SWTUtil.toSWTConstant(verticalAlignment, CENTER));
    boolean grabExcessHorizontalSpace = ConvertTypeUtil.toBoolean(bbElement.getAttribute("grabExcessHorizontalSpace"),
        true);
    buttonBarInfo.setGrabExcessHorizontalSpace(grabExcessHorizontalSpace);
    boolean grabExcessVerticalSpace = ConvertTypeUtil.toBoolean(bbElement.getAttribute("grabExcessVerticalSpace"),
        false);
    buttonBarInfo.setGrabExcessVerticalSpace(grabExcessVerticalSpace);

    IConfigurationElement[] buttonElements = bbElement.getChildren("button");
    if (buttonElements.length > 0) {
      List<ButtonInfo> buttonInfoList = new ArrayList<ButtonInfo>();
      for (IConfigurationElement button : buttonElements) {
        ButtonInfo buttonInfo = parseButtonInfo(button);
        buttonInfoList.add(buttonInfo);
      }
      buttonBarInfo.setButtonInfoList(buttonInfoList);
    }

    String buttonBarAdapterAttribute = bbElement.getAttribute("buttonBarAdapter");
    if (AssertUtil.isNotEmpty(buttonBarAdapterAttribute)) {
      ButtonBarAdapter buttonBarAdapter = createInstence(bbElement, "buttonBarAdapter");
      buttonBarInfo.setButtonBarAdapter(buttonBarAdapter);
    }

    return buttonBarInfo;
  }

  private ButtonInfo parseButtonInfo(IConfigurationElement buttonElement) {
    ButtonInfo buttonInfo = new ButtonInfo();
    String name = buttonElement.getAttribute("name");
    buttonInfo.setName(name);
    String style = buttonElement.getAttribute("style");
    buttonInfo.setStyle(SWTUtil.toSWTConstant(style, PUSH));
    String imagePath = buttonElement.getAttribute("imagePath");
    buttonInfo.setImagePath(imagePath);
    String tooltip = buttonElement.getAttribute("tooltip");
    buttonInfo.setTooltip(tooltip);

    String tablePaneButtonListenerAttribute = buttonElement.getAttribute("listener");
    if (AssertUtil.isNotEmpty(tablePaneButtonListenerAttribute)) {
      TablePaneButtonListener listener = createInstence(buttonElement, "listener");
      buttonInfo.setListener(listener);
    }
    return buttonInfo;
  }

  @SuppressWarnings("unchecked")
  private <T> T createInstence(IConfigurationElement element, String propertyName) {
    try {
      return (T) element.createExecutableExtension(propertyName);
    } catch (CoreException e) {
      logger.error(e.getMessage(), e);
    }
    return null;
  }

}